/*
 * Copyright 2011-2012 OpenAjax Alliance
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

Components.utils.import("resource://oaa-cache-inspector/cache-inspector-common.js");

/* ---------------------------------------------------------------- */
/*                  Initialize namespace properties                 */
/* ---------------------------------------------------------------- */

if (typeof OAA_CI == "undefined") {
  var OAA_CI = {};
}

OAA_CI.DEBUG = true;
OAA_CI.ruleset = null;
OAA_CI.top_location_href = null;

OAA_CI.FIRST  = 0;
OAA_CI.SECOND = 1;
OAA_CI.THIRD  = 2;
OAA_CI.FOURTH = 3;


/**
 * @property sidebar
 *
 * @memberOf OAA_CI
 *
 * @desc The sidebar object implements an informal interface that includes
 *       a views array and functions onLoad, hideMeter and showMeter.
 */

OAA_CI.sidebar = null;

/**
 * @object SidebarInterface
 *
 * @memberOf OAA_CI
 *
 * @desc Define interface members and their types.
 */

OAA_CI.SidebarInterface = {
  views: [], // array of tabpanel view controllers
  onLoad: function () {},
  hideMeter: function () {},
  showMeter: function () {},
  onItemSelectionChange: function () {}
};

/**
 * @function checkInterface
 *
 * @memberOf OAA_CI
 *
 * @desc Check that an object implements an interface.
 */

OAA_CI.checkInterface = function (obj, inf) {
  for (var member in inf) {
    if (typeof obj[member] != typeof inf[member]) {
      OAA_CI_UTILS.console("INTERFACE PROBLEM: Object failed to implement member " + member);
      return false;
    }
  }
  return true;
};

/**
 * @function checkSidebarInterface
 *
 * @memberOf OAA_CI
 *
 * @desc Check that current sidebar implements SidebarInterface.
 */

OAA_CI.checkSidebarInterface = function () {
  if (!OAA_CI.checkInterface(OAA_CI.sidebar, OAA_CI.SidebarInterface))
    alert("SidebarInterface problem!");
};


// nsIWebProgressListener constants
OAA_CI.STATE_STOP        = Components.interfaces.nsIWebProgressListener.STATE_STOP;
OAA_CI.STATE_IS_WINDOW   = Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW;

// object that implements nsIWebProgressListener interface
OAA_CI.progressListener = {

  QueryInterface: function (iid) {
    if (iid.equals(Components.interfaces.nsIWebProgressListener) ||
        iid.equals(Components.interfaces.nsIWebProgressListener2) ||
        iid.equals(Components.interfaces.nsISupportsWeakReference) ||
        iid.equals(Components.interfaces.nsIXULBrowserWindow) ||
        iid.equals(Components.interfaces.nsISupports))
      return this;
    throw Components.results.NS_NOINTERFACE;
  },

  onStateChange: function (webProgress, request, flags, status) {
    if (flags & OAA_CI.STATE_STOP && flags & OAA_CI.STATE_IS_WINDOW) {
      var location_href = webProgress.DOMWindow.location.href;
      OAA_CI_UTILS.console('STATE_STOP: ' + location_href);
      if (location_href == OAA_CI.top_location_href) {
        OAA_CI.updateView();
      }
    }
  },

  onLocationChange: function (webProgress, request, location, flags) {
    if (request) { // ignore call if request arg is null
      OAA_CI.top_location_href = webProgress.DOMWindow.top.location.href;
      OAA_CI.showTransition();
    }
  },

  onProgressChange: function (a, b, c, d, e, f) {},
  onSecurityChange: function (a, b, c) {},
  onStatusChange: function (a, b, c, d) {}

};

/**
 * @function onLoad
 *
 * @desc Handle loading of sidebar by calling the onLoad function
 *       for the particular sidebar that is loading and setting
 *       the state for toolbar and menus.
 */

OAA_CI.onLoad = function(cache) {

  OAA_CI_UTILS.getPreferences();

  var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
    .getInterface(Components.interfaces.nsIWebNavigation)
    .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
    .rootTreeItem
    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
    .getInterface(Components.interfaces.nsIDOMWindow);

  mainWindow.gBrowser.addProgressListener(OAA_CI.progressListener);
  mainWindow.gBrowser.tabContainer.addEventListener("TabSelect", OAA_CI.onTabSelect, false);

  OAA_CI.oaa_log_window = null;
  OAA_CI.oaa_results_window = null;

  if (OAA_CI.DEBUG) OAA_CI.checkSidebarInterface();

  OAA_CI_UTILS.getPreferences();

  OAA_CI.evaluateDocument();
  OAA_CI.sidebar.onLoad();
  
  OAA_CI_UTILS.setStateToolbarAndMenus(mainWindow, true);

};

/**
 * @function onTabSelect
 *
 * @memberOf OAA_CI.lists
 *
 * @desc Respond to a locationChange event by calling the showTransition
 *       function for the current sidebar.
 */

OAA_CI.onTabSelect = function (event) {

  OAA_CI_UTILS.console("onTabSelect");
  OAA_CI.updateView();

};

/**
 * @function showTransition
 *
 * @memberOf OAA_CI
 *
 * @desc Respond to a locationChange event: While new page is loading,
 *       show the progress meter, remove stale data and show message.
 */

OAA_CI.showTransition = function () {

  OAA_CI.sidebar.showMeter();
  var views = OAA_CI.sidebar.views;

  for (var i = 0; i < views.length; i++) {
    var treechildren = views[i].getTreechildren();
    OAA_CI.removeChildNodes(treechildren);
    OAA_CI.addTransitionRow(treechildren);
  }

};

/**
 * @function updateView
 *
 * @memberOf OAA_CI
 *
 * @desc Evaluate the new document; hide the progress meter to indicate
 *       loading of the new page has completed; reset isInitialized
 *       variables for all tab panel views so that subsequent calls to
 *       showCacheItems functions result in repopulation with fresh data.
 *       Call showCacheItems for the currently selected tab panel view.
 */

OAA_CI.updateView = function () {

  OAA_CI.evaluateDocument();
  OAA_CI.sidebar.hideMeter();
  var views = OAA_CI.sidebar.views;

  // Reset all views
  for (var i = 0; i < views.length; i++)
    views[i].isInitialized = false;

  // Call showCacheItems for selected view
  for (var i = 0; i < views.length; i++) {
    if (views[i].tab.selected) {
      views[i].showCacheItems();
      return;
    }
  }

};

/**
 * onUnload
 *
 * @desc onunLoad event handler that resets object properties
 *
 * @return nothing
 */

OAA_CI.onUnload = function(cache) {

  var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
    .getInterface(Components.interfaces.nsIWebNavigation)
    .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
    .rootTreeItem
    .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
    .getInterface(Components.interfaces.nsIDOMWindow);

  mainWindow.gBrowser.removeProgressListener(OAA_CI.progressListener);

  OAA_CI_UTILS.setStateToolbarAndMenus(mainWindow, false);

  OAA_CI.turnOffHighlighting();

};

/**
 * @function updateXULTime
 *
 * @memnberOf OAA_CI
 *
 * @desc Calculates the amount of time to render XUL controls
 */

OAA_CI.updateXULTime = function (start_time) {

  var end_time = new Date().getTime();
  var time = end_time - start_time;

  if (OAA_CI.prog_xul_message) {
  OAA_CI.prog_xul_message.value = "XUL update time: " + time + " milliseconds";
  }

};

/**
 * updateEvaluationResults
 *
 * @desc updates evaluation results window with the results of the last evaluation
 *
 * @return nothing
 */

OAA_CI.updateEvaluationResults = function() {

  if (OAA_CI.oaa_result_window &&
      OAA_CI.oaa_result_window.document) {

    var oaa_result_text = OAA_CI.oaa_result_window.document.getElementById('ID_OAA_RESULT_TEXT');

    if (oaa_result_text &&
        OAA_CI.ruleset.ruleset_result) {
      oaa_result_text.value =  OAA_CI.ruleset.ruleset_result.toString();
    }

    var oaa_result_html = OAA_CI.oaa_result_window.document.getElementById('ID_OAA_RESULT_HTML');
    if (oaa_result_html &&
        OAA_CI.ruleset.ruleset_result) {
      oaa_result_html.value =  OAA_CI.ruleset.ruleset_result.toHTML();
    }

    var oaa_result_xml = OAA_CI.oaa_result_window.document.getElementById('ID_OAA_RESULT_XML');
    if (oaa_result_xml &&
        OAA_CI.ruleset.ruleset_result) {
      oaa_result_xml.value =  OAA_CI.ruleset.ruleset_result.toXML(OAA_CI.ruleset.ruleset_nls);
    }

    var oaa_result_json = OAA_CI.oaa_result_window.document.getElementById('ID_OAA_RESULT_JSON');
    if (oaa_result_json && OAA_CI.ruleset.ruleset_result) {
      oaa_result_json.value =  OAA_CI.ruleset.ruleset_result.toJSON();
    }

    OAA_CI.oaa_result_window.sizeToContent();
  }

};

/**
 * onEvaluationResultsCommand
 *
 * @desc opens the log information window
 *
 * @return nothing
 */

OAA_CI.onEvaluationResultsCommand = function() {

  if (OAA_CI.oaa_result_window &&
      !OAA_CI.oaa_result_window.closed) {
    OAA_CI.updateEvaluationResults();
  }
  else {
    OAA_CI.oaa_result_window = window.open("chrome://oaaruletesting/content/oaa-result-window.xul",
                      "oaaResultWindow", "chrome,centerscreen");
    OAA_CI.oaa_log_window.onload = OAACacheInspector.updateEvaluationResults;
  }

};

/**
 * updateProgress
 *
 * @desc updated progress information on evaluating a document
 *
 * @return nothing
 */

OAA_CI.updateProgress = function (message, percent) {

  if (OAA_CI.prog_meter) {
    OAA_CI.prog_meter.value = percent;
  }

  if (OAA_CI.prog_message) {
    OAA_CI.prog_message.value = message;
  }

};

/**
 * turnOffHighlighting
 *
 * @desc turn off highlighting for the last cache item that was
 *       highlighted (see highlightCacheItem)
 *
 * @return nothing
 */

OAA_CI.turnOffHighlighting = function () {

  if (OAA_CI_UTILS.last_node_highlighted) {
    OAA_CI_UTILS.last_node_highlighted.style.outline = "";
  }

};

/**
 * highlightCacheItem
 *
 * @desc cache_item Object OAA Cache item
 *
 * @return nothing
 */

OAA_CI.highlightCacheItem = function(cache_item) {

  var node = null;
  var pos_top;
  var pos_left;

  // Remove styling from last node with focus
  OAA_CI.turnOffHighlighting();

  if (!cache_item) return;

  // Test to see if the cache item has a dom_element property
  if (cache_item.dom_element) {
    if (cache_item.dom_element.image_only) {
      node = cache_item.dom_element.node.getElementsByTagName("img")[0];
    }
    else {
      node = cache_item.dom_element.node;
    }
  }
  else {
    if (cache_item.type == NODE_TYPE.ELEMENT) {
      node = cache_item.node;
    }
    else {
      node = cache_item.parent_element.node;
    }
  }

  if (node) {
    node.style.outline = "medium solid red";
    // If true, element is aligned with top of scroll area.
    // If false, it is aligned with bottom.
    node.scrollIntoView(false);
    OAA_CI_UTILS.last_node_highlighted = node;
  }

};

/**
 * @function getCacheIdFromTree
 *
 * @memberOf OAA_CI
 *
 * @desc Return the cache ID of a tree element specified by a selection index.
 *
 * @param {XUL tree} tree - XUL tree with selected cache element.
 * @param {int} index - Tree row index of selected cache element.
 */

OAA_CI.getCacheIdFromTree = function (tree, index) {

  var col_id = tree.columns.getFirstColumn();
  return tree.view.getCellValue(index, col_id);

};

/**
 * evaluateDocument
 *
 * @desc opens the log information window
 *
 * @param window Object window object of document to be analyzed
 *
 * @return nothing
 */

OAA_CI.evaluateDocument = function () {

  var doc;
  var title;
  var url;

  // Get reference to the rendered document (Firefox)
  try {
      doc = window.content.document;
      title = doc.title;
      url = window.content.location.href;
  } catch(e) {
      doc  = window.opener.parent.content.document;
      title = doc.title;
      url = window.opener.parent.location.href;
  } // end try

  OAA_CI.updateProgress("", 0);

  OpenAjax.a11y.CONSOLE_MESSAGES = true;
  OpenAjax.a11y.SUPPORTS_EVENT_ANALYSIS = true;  // enable collecting information about events

  var preferences = OAA_CI_UTILS.getPreferences();
 
  var ruleset = OpenAjax.a11y.all_rulesets.getRuleset(preferences.ruleset_id); 
  
  if (ruleset) {
  
    ruleset.setEvaluationLevel(preferences.wcag20_level);
    ruleset.setBrokenLinkTesting(preferences.broken_links);
  
    OAA_CI.ruleset = ruleset.evaluate(url, title, doc, OAA_CI.updateProgress, true);
    OpenAjax.a11y.console("Ruleset results object for: " + ruleset.url);
  }
  else {
    OpenAjax.a11y.console("  ** Ruleset with the id '" + preferences.ruleset_id + "' not found!!");
  }

  OAA_CI_UTILS.result  = null;
  OAA_CI_UTILS.log     = null;

  if (OAA_CI_UTILS && ruleset && ruleset.result) {
    OAA_CI_UTILS.result  = ruleset.result;
    OAA_CI_UTILS.log     = ruleset.log;
  }


};

/**
 * createXULElement
 *
 * @desc creates a XUL element with the specified attributes
 *
 * @param element    String name of XUL element to create
 * @param attributes String Array of strings with the format name=value
 *
 * @return XUL element object
 */

OAA_CI.createXULElement = function (element, attributes) {

  var xul_element = document.createElement(element);

  var attributes_length = attributes.length;

  for (var i=0; i < attributes_length; i++ ) {

     var attribute_value = attributes[i].split('=');

     if ( attribute_value.length == 2) {
       xul_element.setAttribute(attribute_value[0],attribute_value[1]);
     }
     else {
       if ( attribute_value.length == 1) {
         xul_element.setAttribute(attribute_value[0],"");
       }
     }

  } // end loop

  return xul_element;

};

window.addEventListener("load", function () { OAA_CI.onLoad(); }, false);
window.addEventListener("unload", function () { OAA_CI.onUnload(); }, false);
